#pragma once

template <class treal>
class basevec2
{
public:
    treal x;
    treal y;

    basevec2(void)
        :x(0),y(0)
    {
    }

    explicit basevec2(const treal * p)
        :x(p[0]), y(p[1])
    {
    }

    explicit basevec2(treal const& x0, treal const& y0)
        :x(x0), y(y0)
    {
    }

    inline operator treal const*()const
    {
        return &x;
    }

    inline basevec2 & operator *= (treal const& scale)
    {
        x *= scale;
        y *= scale;
        return *this;
    }

    inline basevec2 & operator /= (treal const& scalar)
    {
        return *this *= (1/scalar);
    }

    inline basevec2 const operator / (treal const& scalar)const
    {
        return *this * (1/scalar);
    }

    inline basevec2 const operator-(basevec2 const& v)const
    {
        return basevec2(x - v.x, y - v.y);
    }

    inline basevec2 const operator-()const
    {
        return basevec2(-x, -y);
    }

    inline basevec2 const operator+()const
    {
        return *this;
    }

    inline basevec2 const operator*(basevec2 const& v)const
    {
        return basevec2(x * v.x, y * v.y);
    }

    inline basevec2 const operator/(basevec2 const& v)const
    {
        return basevec2(x / v.x, y / v.y);
    }

    inline basevec2 const operator+(basevec2 const& v)const
    {
        return basevec2(x + v.x, y + v.y);
    }

    inline basevec2 & operator+=(basevec2 const& v)
    {
        x += v.x;
        y += v.y;
        return *this;
    }

    inline basevec2 & operator*=(basevec2 const& v)
    {
        x *= v.x;
        y *= v.y;
        return *this;
    }

    inline basevec2 & operator/=(basevec2 const& v)
    {
        x /= v.x;
        y /= v.y;
        return *this;
    }

    inline basevec2 & operator-=(basevec2 const& v)
    {
        x -= v.x;
        y -= v.y;
        return *this;
    }

    inline basevec2 const operator*(treal const& scale)const
    {
        return basevec2(x * scale, y * scale);
    }

    inline treal getLength()const
    {
        return static_cast<treal>(sqrt(x * x + y * y));
    }

    inline basevec2<treal> normalize()
    {
        return (*this) * (1.0 / getLength());
    }

    inline basevec2<treal> fract()
    {
        return basevec2<treal>(fract(x),
                           fract(y));
    }

    inline basevec2<treal> step(treal const& edge)
    {
        return basevec2<treal>(step(edge, x),
                           step(edge, y));
    }

    inline basevec2<treal> step(basevec2<treal> const& edge)
    {
        return basevec2<treal>(step(edge.x, x),
                           step(edge.y, y));
    }
};

template<class treal> inline
basevec2<treal> const operator*(treal const& scalar, basevec2<treal> const& v)
{
    return v * scalar;
}

typedef basevec2<float> vec2f;
typedef basevec2<double> vec2d;
